#include "redmine_controls.hpp"
#include <algorithm>
#include "data/app_config.hpp"
#include "data/sql_collection_view.hpp"
#include "data/sql_stores.hpp"
#include "fmt/core.h"
#include "gui/controls/custom_controls.hpp"
#include "gui/controls/redmine_controls.hpp"
#include "imgui/IconsFontAwesome4.h"
#include "imgui/imgui.h"
#include "sql/types.hpp"
#include "utils/app_utils.hpp"

namespace ImGui
{
    template <typename T, typename F>
    int vector_index (const std::vector<T> &vec, F &&f)
    {
        if (vec.empty ())
            return -1;
        const int n = static_cast<int> (std::distance (begin (vec), std::find_if (begin (vec), end (vec), [&](const T &t) {
            return f (t);
        })));
        return n == static_cast<int> (size (vec)) ? -1 : n;
    }

    bool SelectRedMineActivity (int *current)
    {
        IM_ASSERT (current != nullptr && "Current == NULL ?");

        bool       changed    = false;
        auto const activities = SqlViewOf (RedMineActivity);
        int const  cnt        = static_cast<int> (activities.size ());
        int idx = vector_index(activities, [current](const RedMineActivity& activity){ return activity.act_id == *current; });

        std::string description = "尚未设置";
        if (idx >= 0 && idx < cnt)
            description = activities[idx].act_name;

        // SetNextItemWidth (400);
        if (BeginCombo ("##RedMineActivitySelector", description.c_str ()))
        {
            int showed = 0;
            for (auto &x: activities)
            {
                if (Selectable (x.act_name.c_str ()))
                {
                    changed  = true;
                    *current = x.act_id;
                }

                if (showed == *current)
                    SetItemDefaultFocus ();

                showed++;
            }

            if (showed == 0)
            {
                BeginDisabled ();
                Selectable ("当前没有任何活动可供选择，请在管理页同步服务器上的活动列表");
                EndDisabled ();
            }

            EndCombo ();
        }

        if (IsItemHovered ())
            SetTooltip ("%s", description.c_str ());

        return changed;
    }

    std::string FormatRedMineIssue (const RedMineIssue &issue)
    {
        return fmt::format ("{}{} - {}", issue.is_closed ? "[已关闭]" : "", issue.project_name, issue.issue_name);
    }

    bool SelectRedMineIssue (int *current)
    {
        IM_ASSERT (current != nullptr && "Current == NULL ?");

        bool       changed     = false;
        auto const issues      = SqlViewOf (RedMineIssue);
        bool const show_closed = !Config::Value (Config::KEY_SHOW_CLOSE_ISSUES).empty ();
        int const  cnt         = static_cast<int> (issues.size ());
        int        showed      = 0;
        int idx = vector_index(issues, [current](const RedMineIssue& issue){ return issue.issue_id == *current; });

        std::string description = "尚未设置";
        if (idx >= 0 && idx < cnt)
            description = issues[idx].issue_name;

        // SetNextItemWidth (400);
        if (BeginCombo ("##RedMineIssueSelector", description.c_str ()))
        {
            bool has_closed = false;
            for (auto &x: issues)
            {
                if (x.is_closed && !has_closed)
                {
                    has_closed = true;
                    if (!show_closed)
                        break;  // do not show
                    PushStyleColor (ImGuiCol_Text, IM_COL32 (255, 255, 0, 255));
                }

                std::string const item_text = FormatRedMineIssue (x);
                if (Selectable (item_text.c_str ()))
                {
                    changed  = true;
                    *current = x.issue_id;
                }

                if (showed == *current)
                    SetItemDefaultFocus ();

                showed++;
            }

            if (showed == 0)
            {
                BeginDisabled ();
                Selectable ("当前没有可展示的问题，请在管理页导入！");
                EndDisabled ();
            }

            if (has_closed)
            {
                if (show_closed)
                    PopStyleColor (1);
                else
                {
                    BeginDisabled (true);
                    PushStyleColor (ImGuiCol_Text, IM_COL32 (255, 255, 0, 255));
                    Selectable (ICON_FA_EXCLAMATION_TRIANGLE " 未展示已关闭的问题 " ICON_FA_EXCLAMATION_TRIANGLE);
                    PopStyleColor (1);
                    EndDisabled();
                }
            }

            EndCombo ();
        }

        if (IsItemHovered ())
            SetTooltip ("%s", description.c_str ());

        return changed;
    }

    bool EditTags (std::vector<Tag> &tags, const std::function<bool (TagEditOperation op, const Tag &data)> &edit_callback)
    {
        bool changed = false;

        struct {
            TagEditOperation op;
            Tag              data;
        } op_data;

        float const max_x = (ImGui::GetContentRegionAvail() + ImGui::GetCursorScreenPos() - ImGui::GetWindowPos()).x;

        SeparatorText("标签列表##Sep");

        if (tags.empty ())
        {
            static const char *tag_unset_text = ICON_FA_INFO_CIRCLE " 尚未设置任何标签 " ICON_FA_INFO_CIRCLE;
            const auto         width          = ImGui::CalcTextSize (tag_unset_text).x;
            ImGui::SetCursorPosX ((max_x - width) / 2.f);
            ImGui::TextUnformatted (tag_unset_text);
        }
        else
        {
            float       used_x = 0;

            // Render Tags
            for (auto &t: tags)
            {
                static const char *buttons[] {ICON_FA_TRASH, nullptr};

                const auto w = ImGui::GetTagRenderWidth (t, buttons);
                if (used_x > 0 && max_x - used_x > w + 100)
                {
                    ImGui::SameLine ();
                }
                else if (used_x > 0)
                {
                    used_x = 0;
                }
                used_x += w;

                ImGui::RenderTag (
                        t, buttons,
                        [tags, &changed, &op_data] (int id, void *data) {
                            const Tag *tag = static_cast<Tag *> (data);
                            if (id == 0)  // Delete
                            {
                                if (tag->tag_level == L_PRIMARY)
                                {
                                    // 删除主标签的时候同时清楚次标签
                                    op_data.op = TagEditOperation_Clear;
                                }
                                else
                                {
                                    op_data.op   = TagEditOperation_Remove;
                                    op_data.data = *tag;
                                }
                                changed = true;
                            }
                        },
                        &t);
            }
        }

        auto const &available_tags = SqlViewOf (Tag);

        if (Button (ICON_FA_PLUS_SQUARE " 添加标签"))
        {
            if (available_tags.empty ())
            {
                ImGui::PushStyleColor (ImGuiCol_Text, IM_COL32 (255, 240, 0, 255));
                SendInfo (ICON_FA_TIMES_CIRCLE " 当前没有定义任何标签，请先添加一些标签！");
                ImGui::PopStyleColor ();
            }
            else
                ImGui::OpenPopup ("标签列表");
        }

        if (ImGui::BeginPopup ("标签列表"))
        {
            ImGui::AlignTextToFramePadding ();
            const bool show_primary  = tags.empty () || std::ranges::all_of (tags, [] (auto &x) { return x.tag_level == L_SECONDARY; });
            int        display_count = 0;
            for (auto &t: available_tags)
            {
                if (t.tag_disabled)  // 禁用的标签不展示
                    continue;
                if (show_primary && t.tag_level != L_PRIMARY)
                    continue;
                if (!show_primary && t.tag_level != L_SECONDARY)
                    continue;
                if (std::ranges::find_if (tags, [id = t.tag_id] (auto &x) { return id == x.tag_id; }) != end (tags))
                    continue;
                auto display = fmt::format (ICON_FA_TAG " [{}] {}", (t.tag_level == L_PRIMARY) ? "主" : "次", t.tag_name);
                if (ImGui::Selectable (display.c_str ()))
                {
                    changed      = true;
                    op_data.op   = TagEditOperation_Add;
                    op_data.data = t;
                }
                ++display_count;
            }
            if (display_count == 0)
            {
                ImGui::PushStyleColor (ImGuiCol_Text, IM_COL32 (255, 240, 0, 255));
                ImGui::Selectable (ICON_FA_FROWN_O " 已经没有可添加的标签了");
                ImGui::PopStyleColor ();
            }
            ImGui::EndPopup ();
        }

        if (changed)
        {
            switch (op_data.op)
            {
            case TagEditOperation_Clear:
                if (!edit_callback || edit_callback (op_data.op, op_data.data))
                    tags.clear ();
                break;
            case TagEditOperation_Remove:
                if (!edit_callback || edit_callback (op_data.op, op_data.data))
                    tags.erase (std::find_if (begin (tags), end (tags), [&op_data] (const Tag &t) { return t.tag_id == op_data.data.tag_id; }));
                break;
            case TagEditOperation_Add:
                if (!edit_callback || edit_callback (op_data.op, op_data.data))
                    tags.emplace_back (op_data.data);
                break;
            }

            // sort, primary first
            std::sort (begin (tags), end (tags), [] (const Tag &a, const Tag &b) { return a.tag_level < b.tag_level; });
        }

        return changed;
    }
}  // namespace ImGui
